package com.program.houai.util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class DateFullUtils {

    private static Logger logger = LoggerFactory.getLogger(DateFullUtils.class);
    public static final String PURE_LONG_DATE_TIME_FORMAT_STR = "yyyyMMddHHmmssSSS";
    public static final String YYYYMMDD = "yyyyMMdd";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YY_MM_DD = "yy-MM-dd";
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
    public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
    public static final String YY = "yy";
    public static final String MM = "MM";
    public static final String DD = "dd";
    public static final String HHMMSSS = "HHmmssSSS";
    public static final String HHMMSS = "HHmmss";
    public static final String DDHHMMSS = "ddHHmmss";

    public DateFullUtils() {
    }

    /**
     * 字符串(yyyy-MM-dd)转date
     *
     * @param dateStr
     * @return
     * @throws Exception
     */
    public static Date getDate(String dateStr) throws Exception {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            return format.parse(dateStr);
        } catch (Exception var2) {
            logger.error(" >>> 日期格式解析发生异常，日期格式不正确。Exception:" + var2.getMessage());
            throw var2;
        }
    }

    /**
     * 字符串(yyyyMMddHHmmss)转date
     *
     * @param dateStr
     * @return
     * @throws Exception
     */
    public static Date getFullDate(String dateStr) throws Exception {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
            return format.parse(dateStr);
        } catch (Exception var2) {
            logger.warn(" >>> 日期格式解析发生异常，日期格式不正确。Exception:" + var2.getMessage());
            throw var2;
        }
    }


    /**
     * 字符串转date(自定义格式)
     * dateFormat就是类开始定义的，直接引用即可
     *
     * @param dateStr
     * @param dateFormat
     * @return
     * @throws Exception
     */
    public static Date getDate(String dateStr, String dateFormat) throws Exception {
        try {
            SimpleDateFormat format = new SimpleDateFormat(dateFormat);
            return format.parse(dateStr);
        } catch (Exception var3) {
            logger.error(" >>> 日期格式解析发生异常，日期格式不正确。Exception:" + var3.getMessage());
            throw var3;
        }
    }

    /**
     * date转字符串(yyyy-MM-dd)
     *
     * @param date
     * @return
     */
    public static String getDateStr(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.format(date);
    }

    /**
     * date转字符串（自定义格式）
     *
     * @param date
     * @param format
     * @return
     */
    public static String getDateStr(Date date, String format) {
        SimpleDateFormat simple = new SimpleDateFormat(format);
        return simple.format(date);
    }

    /**
     * 获取时间戳
     * - 1702369777751
     *
     * @param date
     * @return
     */
    public static long getMillis(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.getTimeInMillis();
    }

    /**
     * 获取时间戳-不含毫秒
     * -1702369820000
     *
     * @param date
     * @return
     */
    public static long getSecondsMillis(Date date) {
        String timestamp = String.valueOf(date.getTime());
        timestamp = timestamp.substring(0, timestamp.length() - 3);
        timestamp = timestamp + "000";
        return Long.valueOf(timestamp);
    }

    public static Date getSecondsDate(Date date) {
        return getDateByTime(getSecondsMillis(date));
    }

    /**
     * 指定时间减去多少天
     *
     * @param date
     * @param day
     * @return
     */
    public static Date diffDate(Date date, int day) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) - (long) day * 24L * 3600L * 1000L);
        return c.getTime();
    }

    /**
     * 指定时间加上多少天
     *
     * @param date
     * @param day
     * @return
     */
    public static Date addDate(Date date, int day) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) + (long) day * 24L * 3600L * 1000L);
        return c.getTime();
    }

    /**
     * 指定时间减去多少小时
     *
     * @param date
     * @param hour
     * @return
     */
    public static Date diffDate4Hour(Date date, int hour) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) - (long) hour * 3600L * 1000L);
        return c.getTime();
    }

    /**
     * 指定时间加上多少小时
     *
     * @param date
     * @param hour
     * @return
     */
    public static Date addDate4Hour(Date date, int hour) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) + (long) hour * 3600L * 1000L);
        return c.getTime();
    }

    /**
     * 指定时间减去多少分钟
     *
     * @param date
     * @param minute
     * @return
     */
    public static Date diffDate4Minute(Date date, int minute) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) - (long) minute * 60L * 1000L);
        return c.getTime();
    }

    /**
     * 指定时间加上多少分钟
     *
     * @param date
     * @param minute
     * @return
     */
    public static Date addDate4Minute(Date date, int minute) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) + (long) minute * 60L * 1000L);
        return c.getTime();
    }


    /**
     * 指定时间加上多少秒
     *
     * @param date
     * @param seconds
     * @return
     */
    public static Date addDate4Second(Date date, int seconds) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(getMillis(date) + (long) seconds * 1000L);
        return c.getTime();
    }

    /**
     * 两个时间相差多少秒
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long compareDate4Second(Date startDate, Date endDate) {
        long l = endDate.getTime() - startDate.getTime();
        return l / 1000L;
    }

    public static boolean compareDate(Date startDate, Date endDate) {
        long l = endDate.getTime() - startDate.getTime();
        if(l > 0){
            return true;
        }
        return false;
    }


    /**
     * 两个时间相差多少分钟(取整数)
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long compareDate4Minute(Date startDate, Date endDate) {
        long l = endDate.getTime() - startDate.getTime();
        return l / 60000L;
    }

    /**
     * 两个时间相差多少分钟(多一秒算一分钟)
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long compareDate4Minute2(Date startDate, Date endDate) {
        long ls = compareDate4Second(startDate, endDate);
        int leftLenSecs = (new Long(ls)).intValue() % 60;
        return leftLenSecs > 0 ? ls / 60L + 1L : ls / 60L;
    }

    /**
     * 两个时间相差多少小时
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long compareDate4Hour(Date startDate, Date endDate) {
        long l = endDate.getTime() - startDate.getTime();
        return l / 3600000L;
    }

    /**
     * 两个时间相差多少天
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long compareDate4Day(Date startDate, Date endDate) {
        long l = endDate.getTime() - startDate.getTime();
        long d = l / 86400000L;
        return d;
    }

    /**
     * 时间戳转date
     *
     * @param time
     * @return
     */
    public static Date getDateByTime(long time) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(time);
        return cal.getTime();
    }

    /**
     * 根据身份证号获取生日年月日
     *
     * @param idCard
     * @return
     */
    public static Date getBirthdayByIdCard(String idCard) {
        String birthday = "";
        if (idCard.length() == 15) {
            birthday = "19" + idCard.substring(6, 12);
        } else if (idCard.length() == 18) {
            birthday = idCard.substring(6, 14);
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        try {
            return sdf.parse(birthday);
        } catch (ParseException var4) {
            var4.printStackTrace();
            return null;
        }
    }

    /***
     * 获取多少天后的开始时间 例如 2018-12-20 00：00：00
     *
     * @param daycCount
     * @return
     */
    public static Date getManyDaysStartTime(Integer daycCount) {
        Calendar startTime = Calendar.getInstance();
        startTime.setTime(new Date());
        startTime.add(Calendar.DATE, -daycCount);
        startTime.set(Calendar.HOUR_OF_DAY, 0);
        startTime.set(Calendar.MINUTE, 0);
        startTime.set(Calendar.SECOND, 0);
        startTime.set(Calendar.MILLISECOND, 0);
        return startTime.getTime();
    }

    /***
     * 获取多少天后的结束时间 例如 2018-12-20 23：59：59
     *
     * @param daysCount
     * @return
     */
    public static Date getManyDaysEndTime(Integer daysCount) {
        Calendar endTime = Calendar.getInstance();
        endTime.setTime(new Date());
        endTime.add(Calendar.DATE, -daysCount);
        endTime.set(Calendar.HOUR_OF_DAY, 23);
        endTime.set(Calendar.MINUTE, 59);
        endTime.set(Calendar.SECOND, 59);
        endTime.set(Calendar.MILLISECOND, 999);
        return endTime.getTime();
    }

    /**
     * date2比date1多的天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDays(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if (year1 != year2)   //不同一年
        {
            int timeDistance = 0;
            for (int i = year1; i < year2; i++) {
                if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)    //闰年
                {
                    timeDistance += 366;
                } else    //不是闰年
                {
                    timeDistance += 365;
                }
            }

            return timeDistance + (day2 - day1);
        } else    //同一年
        {
            return day2 - day1;
        }
    }

    /***
     *
     * 1获取最近几个月的第1天和最后1天
     *
     * @param monthType 1 判断最近月份的第1天 2 获取最近月份的最后1天
     * @param month     月份
     * @return
     */
    public static String getMonthType(int monthType, int month) {
        Calendar cale = null;
        cale = Calendar.getInstance();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        if (monthType == 1) {
            cale.add(Calendar.MONTH, -(month - 1));
            cale.set(Calendar.DAY_OF_MONTH, 1);
            return format.format(cale.getTime());
        } else {
            cale.add(Calendar.MONTH, month);
            cale.set(Calendar.DAY_OF_MONTH, 0);
            return format.format(cale.getTime());
        }
    }

    /**
     * 获取指定时间的月初和月末
     *
     * @param day  指定时间
     * @param type 0=月初 00：00：00  1=月末 23:59:59
     * @return
     */
    public static Date getMonthStartAndEndDateTime(Date day, int type) {
        LocalDateTime now = day.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime first = LocalDateTime.of(now.getYear(), now.getMonth(), 1, 0, 0, 0, 0);
        LocalDateTime last = LocalDateTime.of(first.with(TemporalAdjusters.lastDayOfMonth()).getYear(),
                first.with(TemporalAdjusters.lastDayOfMonth()).getMonth(),
                first.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth(), 23, 59, 59);
        if (0 == type) {
            return Date.from(first.atZone(ZoneId.systemDefault()).toInstant());
        } else {
            return Date.from(last.atZone(ZoneId.systemDefault()).toInstant());
        }
    }

    /**
     * 获取指定日期的开始和结束时间
     *
     * @param date
     * @param type 0=日初 1=日末
     * @return
     * @throws ParseException
     */
    public static Date getDayStartAndEndDateTime(Date date, int type) throws ParseException {
        if (0 == type) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(date);
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
            return instance.getTime();
        } else {
            Calendar instance = Calendar.getInstance();
            instance.setTime(date);
            instance.set(Calendar.HOUR_OF_DAY, 23);
            instance.set(Calendar.MINUTE, 59);
            instance.set(Calendar.SECOND, 59);
            return instance.getTime();
        }
    }

    /**
     * 获取几个月前的月初时间或月末时间
     *
     * @param date
     * @param months 如果为负数就是几个月前  如果为正数就是几个月后
     * @param type
     * @return
     * @throws ParseException
     */
    public static Date getDateAddMonths(Date date, int months, int type) throws ParseException {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.add(Calendar.MONTH, months);
        if (0 == type) {
            instance.set(Calendar.HOUR_OF_DAY, 0);
            instance.set(Calendar.MINUTE, 0);
            instance.set(Calendar.SECOND, 0);
        } else {
            instance.set(Calendar.HOUR_OF_DAY, 23);
            instance.set(Calendar.MINUTE, 59);
            instance.set(Calendar.SECOND, 59);
        }
        return instance.getTime();
    }


    /**
     * 获取指定日期是周几
     *
     * @param date
     * @return
     */
    public static int getDayIndexOfWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int whichDay1 = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (whichDay1 == 0) {
            whichDay1 = 7;
        }
        return whichDay1;
    }

    /**
     * 判断选择的日期本月的第几天
     */
    public static int getDayIndexOfMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 判断选择的时间是指定日期的第几个小时
     */
    public static int getHourIndexOfDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.HOUR_OF_DAY);
    }

    /**
     * 判断now时间是否在指定时间段内
     * 注意时间格式：String format = "HH:mm:ss";
     *
     * @param nowTimeStr
     * @param startTimeStr
     * @param endTimeStr
     * @return
     */
    public static boolean isEffectiveTime(String nowTimeStr, String startTimeStr, String endTimeStr) {
        String format = "HH:mm:ss";
        SimpleDateFormat sf = new SimpleDateFormat("HH:mm:ss");
        String now = sf.format(new Date());
        if (StringUtils.isNotBlank(nowTimeStr)) {
            now = nowTimeStr;
        }
        Date nowTime;
        try {
            nowTime = new SimpleDateFormat(format).parse(now);
            Date startTime = new SimpleDateFormat(format).parse(startTimeStr);
            Date endTime = new SimpleDateFormat(format).parse(endTimeStr);
            if (isEffectiveDate(nowTime, startTime, endTime)) {
                return true;
            } else {
                return false;
            }
        } catch (ParseException e) {
            // e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致
     *
     * @param nowTime   当前时间
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     * @author jqlin
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime() || nowTime.getTime() == endTime.getTime()) {
            return true;
        }
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);
        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);
        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取指定时间内的月时间
     * 就是比如穿了一个2021年1月份  一个2021年3月份  格式就是yyyyMM
     * 返回 列表202101 202102 202103
     *
     * @param minDate
     * @param maxDate
     * @return
     * @throws Exception
     */
    public static List<String> getMonthBetween(Date minDate, Date maxDate, String format) throws Exception {
        ArrayList<String> result = new ArrayList<String>();
        SimpleDateFormat sdf = new SimpleDateFormat(format);// 格式化为年月
        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();
        min.setTime(minDate);
        min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);// 设置年月日，最少3个参数
        max.setTime(maxDate);
        max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
        Calendar curr = min;
        while (curr.before(max)) {
            result.add(sdf.format(curr.getTime()));
            curr.add(Calendar.MONTH, 1);
        }
        return result;
    }

    /**
     * 获取指定时间内的天时间
     * 同上返回指定格式的天数20210101 20210102 20210103....
     *
     * @param minDate
     * @param maxDate
     * @return
     * @throws Exception
     */
    public static List<String> getDayBetween(Date minDate, Date maxDate, String format) throws Exception {
        ArrayList<String> result = new ArrayList<String>();
        SimpleDateFormat sdf = new SimpleDateFormat(format);// 格式化为年月
        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();
        min.setTime(minDate);
        max.setTime(maxDate);
        Calendar curr = min;
        while (curr.before(max) || curr.compareTo(max) == 0) {
            result.add(sdf.format(curr.getTime()));
            curr.add(Calendar.DAY_OF_MONTH, 1);
        }
        return result;
    }

    /**
     * 返回指定时间所在周的周一和周日时间
     *
     * @param date
     * @return
     */
    public static List<Date> getWeekStartEnd(Date date) {
        List<Date> result = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        // 获取本周的第一天（周一）
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        Date weekStartDate = calendar.getTime();

        // 获取本周的最后一天（周日）
        calendar.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndDate = calendar.getTime();
        try {
            result.add(getDayStartAndEndDateTime(weekStartDate, 0));
            result.add(getDayStartAndEndDateTime(weekEndDate, 1));
        } catch (Exception e) {

        }
        return result;
    }

    /**
     * 判断两个时间是否在同一个月份
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean areDatesInSameMonth(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);

        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);

        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) &&
                calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
    }

    /**
     * 判断两个时间是否在同一周
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isInSameWeek(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(date1);
        cal2.setTime(date2);

        int week1 = cal1.get(Calendar.WEEK_OF_YEAR);
        int week2 = cal2.get(Calendar.WEEK_OF_YEAR);
        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);

        return (year1 == year2) && (week1 == week2);
    }


    public static void main(String[] args) throws Exception {
        String dateStr = "20180129123050";
        String dateStr2 = "20180129123352";
        long date = compareDate4Minute2(getDate(dateStr, YYYYMMDDHHMMSS), getDate(dateStr2, YYYYMMDDHHMMSS));
        System.out.println(date);
    }
}